using System;
using UnityEngine;
using System.Collections.Generic;
using log4net.Core;

namespace GameCore
{
    public class GridInventory : Inventory
    {
        public Transform cellRoot;
        public SimpleCell cellPrefab;
        public List<SimpleCell> _cells = new();

        protected virtual void Start()
        {
            SpawnCells();
        }
        
        private void SpawnCells()
        {
            if (!cellRoot) cellRoot = transform;
            foreach (var pos in shape)
            {
                var cell = Instantiate(cellPrefab, cellRoot);
                cell.transform.localPosition = new Vector3(pos.x + cell.offset.x, pos.y + cell.offset.y, cell.offset.z);
                cell.inventory = this;
                cell.gridPos = pos;
                _cells.Add(cell);
            }
        }

        public override void ResetData()
        {
            SetData(new InventoryData(resourceID, shape));
        }
        
        public override void SetData(GameData newData)
        {
            if (newData is null || newData is not InventoryData inventoryData) return;
            if (inventoryData.id != resourceID)
                throw new Exception($"Inventory not match!, Trying to set [{inventoryData.id}] data to inventory [{resourceID}]");
            // Destroy current grid item instances
            if (data is not null) DestroyAllItems();
            data = inventoryData;
            foreach (var item in inventoryData.GetAllItems())
            {
                var gridItem = PrefabFactory.CreateInstance<GridItem>(item.data.ItemID);
                gridItem.SetData(item.data);
                PlaceGridItem(item.gridPos, gridItem);
            }
        }
        
        #region Item Management
        
        protected readonly Dictionary<Vector2Int, GridItem> gridItems = new();

        public override bool ValidatePlaceItem(Vector2Int gridPos, GridItem item)
        {
            var offsetShape = item.shape.Clone();
            offsetShape.Translate(gridPos);
            return data.HasSpace(offsetShape);
        }

        protected void PlaceGridItem(Vector2Int gridPos, GridItem item)
        {
            item.transform.parent = cellRoot;
            item.transform.localPosition = new Vector3(gridPos.x, gridPos.y, -0.002f);
            item.gridPos = gridPos;
            item.parentInventory = this;
            item.placed = true;
            gridItems.Add(gridPos, item);
        }

        public override void PlaceItem(Vector2Int gridPos, GridItem item)
        {
            PlaceGridItem(gridPos, item);
            data.PlaceItem(gridPos, item.itemData, item.shape);
            LevelManager.RaiseEvent(new ItemPlacedEvent(item, this));
        }

        protected GridItem GetGridItem(Vector2Int gridPos)
        {
            var itemData = data.GetItem(gridPos);
            if (itemData is null) return null;
            var center = data.GetCenter(itemData);
            return gridItems[center.gridPos];
        }

        public override GridItem RemoveItem(Vector2Int gridPos)
        {
            var itemData = data.GetItem(gridPos);
            if (itemData is null) return null;
            var center = data.GetCenter(itemData);
            data.RemoveItem(gridPos);
            if (!gridItems.Remove(center.gridPos, out var item)) return null;
            item.transform.parent = null;
            item.placed = false;
            
            return item;
        }

        public override void DestroyItem(Vector2Int gridPos)
        {
            if (!gridItems.Remove(gridPos, out var item)) return;
            Destroy(item.gameObject);
        }

        private void DestroyAllItems()
        {
            foreach (var (pos, gridItem) in gridItems)
            {
                if (gridItem != null) Destroy(gridItem.gameObject);
            }
            gridItems.Clear();
        }

        #endregion
        
        public override void OnCellClicked(Vector2Int gridPos)
        {
            GetGridItem(gridPos)?.OnClick();
        }

        public override void PreviewPlaceItem(GridItem item, Vector2Int gridPos)
        {
            var offsetShape = item.shape.Clone();
            offsetShape.Translate(gridPos);
            var success = data.HasSpace(offsetShape);
            foreach (var cell in _cells)
            {
                
                if (offsetShape.ContainsCell(cell.gridPos))
                {
                    if (success) cell.SetSuccess();
                    else cell.SetError();
                }
                else
                {
                    cell.SetNormal();
                }
            }
        }

        public override void ClearPreview()
        {
            foreach (var cell in _cells)
            {
                cell.SetNormal();
            }
        }

        public void ClearItemPlacementPreview()
        {
            foreach (var cell in _cells) cell.SetNormal();
        }
        
        #region Gizmos Debug

        public bool debug = true;
        public GizmosDebug.DrawShapeSettings gizmosDrawSettings;
        public void OnDrawGizmosSelected()
        {
            if (!debug) return;
            GizmosDebug.DrawShape(shape, cellRoot.position, gizmosDrawSettings);
        }

        #endregion
    }
}